package com.bolt.support.spring.jpa.handler;


import com.bolt.common.utils.StrUtil;
import com.bolt.support.spring.jpa.annotation.QueryBuild;
import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.TreeTranslator;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.ListBuffer;

import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.TypeVariable;
import javax.tools.Diagnostic;
import java.util.ArrayList;
import java.util.Set;

@SupportedSourceVersion(SourceVersion.RELEASE_8)
@SupportedAnnotationTypes("com.bolt.support.spring.jpa.annotation.QueryBuild")
public class QueryBuildHandler extends BaseProcessor {


    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        Set<? extends Element> get = roundEnv.getElementsAnnotatedWith(QueryBuild.class);
        QueryBuildScanner buildScanner = new QueryBuildScanner(this.processingEnv);
        for (Element element : get) {

            addImportInfo(element, "com.bolt.support.spring.jpa.jpql", "Clauses");
            addImportInfo(element, "com.bolt.support.spring.jpa.jpql", "ColumnClause");
            addImportInfo(element, "com.bolt.support.spring.jpa.jpql", "EntityClause");
            java.util.List<VariableElement> fields = new ArrayList<>();
            buildScanner.getVariable(element.asType(), fields, true);
            // 获取当前类的抽象语法树
            final JCTree tree = javacTrees.getTree(element);

            tree.accept(new TreeTranslator() {
                @Override
                public void visitImport(JCTree.JCImport jcImport) {
                    super.visitImport(jcImport);
                }

                @Override
                public void visitClassDef(JCTree.JCClassDecl jcClassDecl) {

                    fields.stream()
                            // 类型强转
                            .forEach(it -> {
                                TypeMirror fieldType = getTypeMirror(it, jcClassDecl);
                                String packageName = StrUtil.subBefore(fieldType.toString(), StrUtil.DOT, true);
                                String className = StrUtil.subAfter(fieldType.toString(), StrUtil.DOT, true);
                                addImportInfo(element, packageName, className);
                                // 对于变量进行生成方法的操作
                                String fieldName = it.getSimpleName().toString();
                                jcClassDecl.defs = jcClassDecl.defs.prepend(genNewColumnClauseMethod(fieldName, fieldType, jcClassDecl));

                            });
                    jcClassDecl.defs = jcClassDecl.defs.prepend(genNewEntityClauseMethod(jcClassDecl));
                    super.visitClassDef(jcClassDecl);
                }
            });
        }

        return true;
    }

    private JCTree.JCMethodDecl genNewEntityClauseMethod(JCTree.JCClassDecl jcClassDecl) {
        // 生成return语句，return this.xxx
        JCTree.JCReturn returnStatement = treeMaker.Return(


                treeMaker.NewClass(
                        null, //尚不清楚含义
                        List.nil(), //泛型参数列表
                        treeMaker.Ident(names.fromString("EntityClause")), //创建的类名
                        List.of(treeMaker.Select(
                                treeMaker.Ident(jcClassDecl.sym.name),
                                names.fromString("class")
                        )), //参数列表
                        null //类定义，估计是用于创建匿名内部类
                )
        );
        ListBuffer<JCTree.JCStatement> statements = new ListBuffer<JCTree.JCStatement>()
                .append(returnStatement);


        JCTree.JCExpression returnMethodType = createTypeApply("EntityClause", createTypeargs(jcClassDecl.sym.name.toString()));
        //treeMaker.Ident(names.fromString("ColumnClause<UserEntity>"));
        // 生成方法体
        JCTree.JCBlock body = treeMaker.Block(0, statements.toList());

        // 生成方法定义树节点
        return treeMaker.MethodDef(
                // 方法访问级别修饰符
                treeMaker.Modifiers(Flags.PUBLIC + Flags.STATIC),
                // get 方法名
                names.fromString("table"),
                // 返回值类型
                returnMethodType,
                // 泛型参数列表
                List.nil(),
                //参数值列表
                List.nil(),
                // 异常抛出列表
                List.nil(),
                // 方法默认体
                body,
                // 默认值
                null
        );

    }

    private JCTree.JCMethodDecl genNewColumnClauseMethod(String fieldName, TypeMirror fieldType, JCTree.JCClassDecl jcClassDecl) {

        // 生成return语句，return this.xxx
        JCTree.JCReturn returnStatement = treeMaker.Return(

                treeMaker.NewClass(
                        null, //尚不清楚含义
                        List.nil(), //泛型参数列表
                        treeMaker.Ident(names.fromString("ColumnClause")), //创建的类名
                        List.of(treeMaker.Literal(fieldName), treeMaker.Select(
                                treeMaker.Ident(jcClassDecl.sym.name),
                                names.fromString("class")
                        )), //参数列表
                        null //类定义，估计是用于创建匿名内部类
                )
        );

        ListBuffer<JCTree.JCStatement> statements = new ListBuffer<JCTree.JCStatement>()
                .append(returnStatement);

        JCTree.JCExpression returnMethodType = createTypeApply("ColumnClause", createTypeargs(StrUtil.subAfter(fieldType.toString(), StrUtil.DOT, true)));
        //treeMaker.Ident(names.fromString("ColumnClause<UserEntity>"));
        // 生成方法体
        JCTree.JCBlock body = treeMaker.Block(0, statements.toList());

        // 生成方法定义树节点
        return treeMaker.MethodDef(
                // 方法访问级别修饰符
                treeMaker.Modifiers(Flags.PUBLIC + Flags.STATIC),
                // get 方法名
                names.fromString(fieldName),
                // 返回值类型
                returnMethodType,
                // 泛型参数列表
                List.nil(),
                //参数值列表
                List.nil(),
                // 异常抛出列表
                List.nil(),
                // 方法默认体
                body,
                // 默认值
                null
        );
    }

    private TypeMirror getTypeMirror(VariableElement fieldElement, JCTree.JCClassDecl jcClassDecl) {


        TypeMirror fieldType = fieldElement.asType();
        if (fieldType.getKind() == TypeKind.TYPEVAR) {
            Element enclosingElement = fieldElement.getEnclosingElement();
            TypeMirror superType = enclosingElement.asType();
            processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, ">>> enclosingElement." + superType);
            processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, ">>> ConstantValue." + fieldElement.getConstantValue());
            TypeVariable typeVar = (TypeVariable) fieldType;
            return typeVar.getUpperBound();
        } else {
            return fieldType;
        }
    }


}


